package furn.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import furn.bean.Furn;
import furn.service.FurnService;
import furn.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.mockito.internal.util.StringUtil;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;

/**
 * 1. 因为当前项目是前后端分离的，在默认情况下，前端发出请求
 * 2. 后端返回json数据，为了方便，我们就在类上使用@RestContrller
 */
@SuppressWarnings("all")
@RestController
@Slf4j
public class FurnController {

    //注入Service接口对象
    @Resource
    private FurnService furnService;

    /**
     * 编写方法，完成数据添加
     * 1. 前端如果是以json格式来发送添加信息furn， 那么需要使用 @RequestBody
     * , 才能将数据封装到对应的bean。同时保证http的请求头的 content-type 是对应的 application/json
     * 2. 如果前端是以表单形式【或地址栏参数形式】提交数据，会自动进行对象参数封装，不需要使用 @RequestBody。
     * 同时保证http请求头的 content-type 是对应的 multipart/form-data
     * 3、@Validated注解 表示 后端会对 对象参数进行校验,并把错误信息封装到errors对象中
     *
     * @param furn
     * @return
     */
    @PostMapping("/save")
    public Result save(@Validated @RequestBody Furn furn, Errors errors) {
        //如果出现校验错误，springboot底层会把错误信息封装到errors对象中

        //定义map ,把errors中的校验错误放入到map.
        //如果有错误信息,就不真正添加，并且将错误信息通过map返回给客户端。客户端就可以取出显示
        HashMap<String, Object> map = new HashMap<>();
        //获取所有字段的校验结果
        List<FieldError> fieldErrors = errors.getFieldErrors();
        //遍历errors中的错误信息，将错误信息放入map中
        for (FieldError fieldError : fieldErrors) {
            //将各字段的名字和错误信息封装到map集合中
            map.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        if (map.isEmpty()) {   //如果map为空，说明没有错误信息，正常添加
            log.info("添加数据：{}", furn);
            furnService.save(furn);
            //调用工具类中的成功方法。不携带数据
            return Result.success();
        } else {
            //如果map不为空，说明有错误信息，返回错误信息给客户端
            return Result.error("400", "后端校验失败", map);
        }

    }

    /**
     * 编写方法，显示家居信息
     */
    @GetMapping("/show")
    public Result show() {
        List<Furn> furns = furnService.list();
        //查询数据，因此要携带数据返回给前端
        return Result.success(furns);
    }

    /**
     * 修改家居信息
     * 1、将前端修改的家居信息封装到furn对象中，以json格式提交给后端
     * 2、@PutMapping 注解 是restful风格的请求。表示修改数据
     *
     * @param furn
     * @return
     */
    @PutMapping("/update")
    public Result update(@RequestBody Furn furn) {
        //调用service层方法。该方法是mybatis-plus提供的方法
        furnService.updateById(furn);
        return Result.success();
    }

    /**
     * 删除家居信息
     * 1、使用url占位符和@PathVariable注解，将占位符的值绑定到id变量中
     *
     * @param id
     * @return
     */
    @DeleteMapping("/delete/{id}")
    public Result delete(@PathVariable Integer id) {
        //该方法是mybatis-plus提供的方法
        furnService.removeById(id);
        return Result.success();
    }

    /**
     * 根据id查询家居信息
     * 1、使用url占位符和@PathVariable注解，将占位符的值绑定到id变量中
     *
     * @param id
     * @return
     */
    @GetMapping("/findById/{id}")
    public Result findById(@PathVariable Integer id) {
        Furn furn = furnService.getById(id);
        log.info("查询家居信息：{}", furn);
        return Result.success(furn);
    }


    /**
     * 实现分页查询
     * @param pageNum  表示当前页码
     * @param pageSize 表示每页显示的条数
     * @return
     */
    @GetMapping("/findByPage")
    public Result findByPage(@RequestParam(defaultValue = "1") Integer pageNum,
                             @RequestParam(defaultValue = "5") Integer pageSize) {
        //通过page方法，返回一个page对象，该对象中封装了分页数据
        Page<Furn> page = furnService.page(new Page<>(pageNum, pageSize));
        //这里我们注意观察，返回的page数据结构是如何的?这样你才能指定在前端如何绑定返回的数据
        //数据在 data 中的 records属性内
        return Result.success(page);
    }


    /**
     * 实现条件查询分页
     * @param pageNum  表示当前页码
     * @param pageSize 表示每页显示的条数
     * @param search   表示查询条件。即家居名，默认为空
     * @return
     */
    @GetMapping("/findByConditionPage")
    public Result findByConditionPage(@RequestParam(defaultValue = "1") Integer pageNum,
                                      @RequestParam(defaultValue = "5") Integer pageSize,
                                      @RequestParam(defaultValue = "") String search) {
        //1、先创建QueryWrapper对象，将检索条件封装到QueryWrapper对象中【可以多个检索条件】
        QueryWrapper<Furn> queryWrapper = Wrappers.query();
        //2、判断search是否为空，如果为空，则查询所有数据，如果不为空，则根据search查询
        if (StringUtils.hasText(search)) {
            //name 属性 是对应的数据表中的字段
            queryWrapper.like("name", search);
        }
        //3、调用service层方法，返回page对象
        Page<Furn> page = furnService.page(new Page<>(pageNum, pageSize), queryWrapper);
        return Result.success(page);
    }

    //编写方法，使用LambdaQueryWrapper封装查询条件，完成检索
    @GetMapping("/findByConditionPage2")
    public Result findByConditionPage2(@RequestParam(defaultValue = "1") Integer pageNum,
                                       @RequestParam(defaultValue = "5") Integer pageSize,
                                       @RequestParam(defaultValue = "") String search) {
        //1、创建LambdaQueryWrapper，封装查询条件
        LambdaQueryWrapper<Furn> lambdaQueryWrapper = Wrappers.<Furn>lambdaQuery();
        //2、判断search是否为空，如果为空，则查询所有数据，如果不为空，则根据search查询
        if (StringUtils.hasText(search)) {
            lambdaQueryWrapper.like(Furn::getName, search);
        }
        //3、调用service层方法，返回page对象
        Page<Furn> page = furnService.page(new Page<>(pageNum, pageSize), lambdaQueryWrapper);
        return Result.success(page);
    }

}
